package edu.ccut.saturn.studio.database.model;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.w3c.dom.Document;
import org.w3c.dom.Node;

import edu.ccut.saturn.studio.core.exception.XMLException;
import edu.ccut.saturn.studio.core.saturnproperty.StringUtils;
import edu.ccut.saturn.studio.core.util.eclipse.SaturnEclipsePathUtil;
import edu.ccut.saturn.studio.core.util.log.ILogger;
import edu.ccut.saturn.studio.core.util.log.SaturnLoggerManager;
import edu.ccut.saturn.studio.core.util.xml.SaturnW3CUtil;

/**
 * 通过xml存取数据库连接信息
 * 
 * @author 谷钰
 * @version 1.0 2008.12.02
 * 
 */
public class DBConnectionProvider {
	public static ILogger logger = SaturnLoggerManager.getInstance()
			.getSaturnLogger(SaturnLoggerManager.BUNDLE_DATABASE);

	private static final String ATTR_DRIVER_PATH_KEY = "driverPath";
	private static final String ATTR_PASSWORD_KEY = "password";
	private static final String ATTR_USER_KEY = "userid";
	private static final String ATTR_URL_KEY = "url";
	private static final String ATTR_DRIVER_KEY = "driverClassName";
	private static final String ATTR_DIALECT_KEY = "dialectName";
	private static final String ATTR_NAME_KEY = "connectionName";
	private static final String NODE_CONNECT_KEY = "connect";
//	private static final String ATTR_DB_NAME = "dbName";

	private Map<String, DBConnection> dbConnections = new LinkedHashMap<String, DBConnection>();

	private static DBConnectionProvider instance = null;

	static {
		instance = new DBConnectionProvider();
	}

	private DBConnectionProvider() {
		try {
			this.initalDbConnection();
		} catch (XMLException e) {
			logger.warn("inital DBConnectionProvider failed!", e);
		}
	}

	public static DBConnectionProvider getInstance() {
		return instance;
	}

	public void addConnection(DBConnection connection) throws XMLException {
		this.dbConnections.put(connection.getName(), connection);
		this.writeXml(connection);
	}

	public Collection<DBConnection> getAllDBConnections() {
		return this.dbConnections.values();
	}
	
	public List<String> getAllDBConnectionNames() {
		return new ArrayList<String>(this.dbConnections.keySet());
	}

	public void removeDBConnection(DBConnection dbconnection) throws Exception {
		this.dbConnections.remove(dbconnection.getName());
		this.removeXml(dbconnection.getName());
	}

	public DBConnection getConnection(String name) {
		return this.dbConnections.get(name);
	}

	private void removeXml(String str) throws XMLException {
		Document doc = getDocument();
		Node root = doc.getDocumentElement();
		Node node = SaturnW3CUtil.getChildByNameAndAttribute(root,
				NODE_CONNECT_KEY, ATTR_NAME_KEY, str);
		root.removeChild(node);
		SaturnW3CUtil.format(root);

		SaturnW3CUtil.writeDocument(doc, SaturnEclipsePathUtil.getDataBaseFile()
				.getPath());
	}

	private void writeXml(DBConnection connection) throws XMLException {
		Document doc = getDocument();
		if (doc != null) {
			Node root = doc.getDocumentElement();

			Node connectionNode = SaturnW3CUtil.createChildNode(root,
					NODE_CONNECT_KEY, null);

			SaturnW3CUtil.createAttribute(connectionNode, ATTR_NAME_KEY,
					connection.getName());
			SaturnW3CUtil.createAttribute(connectionNode, ATTR_DIALECT_KEY,
					connection.getType());
			SaturnW3CUtil.createAttribute(connectionNode, ATTR_DRIVER_KEY,
					connection.getDriverClassName());
			SaturnW3CUtil.createAttribute(connectionNode, ATTR_URL_KEY,
					connection.getUrl());
			SaturnW3CUtil.createAttribute(connectionNode, ATTR_USER_KEY,
					connection.getUsername());
			//todo
//			SaturnW3CUtil.createAttribute(connectionNode, ATTR_DB_NAME,
//					connection.getDBName());
			
			SaturnW3CUtil.createAttribute(connectionNode, ATTR_PASSWORD_KEY,
					connection.getPassword());
			SaturnW3CUtil.createAttribute(connectionNode, ATTR_DRIVER_PATH_KEY,
					connection.getDriverPath());

			SaturnW3CUtil.format(root);
			SaturnW3CUtil.writeDocument(doc, SaturnEclipsePathUtil
					.getDataBaseFile().getPath());
		}
	}

	private void initalDbConnection() throws XMLException {
		Document doc = this.getDocument();
		if (doc != null) {
			Node root = doc.getDocumentElement();
			List<Node> connectionNodes = SaturnW3CUtil.getChildrenByName(root,
					NODE_CONNECT_KEY);

			if (connectionNodes != null) {
				for (Node connectionNode : connectionNodes) {
					String connectionName = SaturnW3CUtil.getNodeAttributeValue(
							connectionNode, ATTR_NAME_KEY);

					String dialectName = SaturnW3CUtil.getNodeAttributeValue(
							connectionNode, ATTR_DIALECT_KEY);
					String driverClassName = SaturnW3CUtil
							.getNodeAttributeValue(connectionNode,
									ATTR_DRIVER_KEY);
					String url = SaturnW3CUtil.getNodeAttributeValue(
							connectionNode, ATTR_URL_KEY);
					String userid = SaturnW3CUtil.getNodeAttributeValue(
							connectionNode, ATTR_USER_KEY);
//					String dbName = SaturnW3CUtil.getNodeAttributeValue(
//							connectionNode, ATTR_DB_NAME);
					String password = SaturnW3CUtil.getNodeAttributeValue(
							connectionNode, ATTR_PASSWORD_KEY);
					String driverPath = SaturnW3CUtil.getNodeAttributeValue(
							connectionNode, ATTR_DRIVER_PATH_KEY);

					DBConnection connection = new DBConnection(connectionName);
					connection.setType(dialectName);
					connection.setDriverClassName(driverClassName);
					connection.setUrl(url);
					connection.setUsername(userid);
//					connection.setDBName(dbName);
					
					connection.setPassword(password);
					connection.setDriverPath(driverPath);

					this.dbConnections.put(connection.getName(), connection);
				}
			}
		}
	}

	private Document getDocument() throws XMLException {
		File file = SaturnEclipsePathUtil.getDataBaseFile();

		if (!file.exists()) {
			this.createDataBaseFile();
		}

		return SaturnW3CUtil.getDocument(file.getPath());
	}

	private void createDataBaseFile() {
		Writer out = null;

		try {
			File xmlFile = SaturnEclipsePathUtil.getDataBaseFile();

			out = new BufferedWriter(new OutputStreamWriter(
					new FileOutputStream(xmlFile), StringUtils.ENCODING));

			String str = "<?xml version=\"1.0\" encoding=\""
					+ StringUtils.ENCODING + "\"?>\n" + "<saturn_database>\n"
					+ "</saturn_database>";
			out.write(str);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (out != null) {
				try {
					out.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
}
